#ifndef PRYN_STATE_H
#define PRYN_STATE_H

#include <pryn/platform.h>

typedef struct PrynState PrynState; /// Complete Pryn state information.
typedef unsigned int PrynResourceIndex;

#ifdef PrynAllocationTracker
typedef struct PrynAllocation PrynAllocation;
#endif /* PrynAllocationTracker */

#include <pryn/factory.h>
#include <pryn/library.h>
#include <pryn/mediator.h>
#include <pryn/pin.h>
#include <pryn/type.h>
#include <pryn/platform.h>
#include <pryn/result.h>
#include <pryn/string.h>
#include <pryn/tag.h>
#include <pryn/utility.h>

PrynCallbackTypedef (PrynResult, PrynFreeFunction, (PrynState *state, void *pointer)); /// Function signature for freeing data from Pryn state.
PrynCallbackTypedef (PrynResult, PrynAllocateFunction, (PrynState *state, size_t length, void **output)); /// Function signature for allocating data for Pryn state.
PrynCallbackTypedef (PrynResult, PrynPrintFunction, (PrynState *state, const PrynString *string)); /// Function signature for printing text.

#ifdef PrynAllocationTracker
#ifdef PrynInternalStructs
/// An allocation record, immediately followed by the allocation data.
struct PrynAllocation
{
#ifdef PrynInternal
	PrynAllocation *pNext, *pPrevious; /// Next and previous allocations.
	size_t pSize; /// Size of the allocation in bytes, not including this record.
	const char *pFilename; /// Allocating source filename.
	size_t pLine; /// One-based allocating source line index. The 32nd bit (mask 1 << 31) is also used to indicate that the allocation has been printed.
#endif /* PrynInternal */
};
#endif /* PrynInternalStructs */
#endif /* PrynAllocationTracker */

/** @defgroup PrynState PrynState C API
	@{ */

PrynImport (PrynResult, prynStateCreate, (PrynState **state))
	/**< @brief Create a state using a default allocator.
	
	Use #prynStateCreateWithAllocator to use a custom allocator.

	@param[out] state Receives the new state object, or 0 if there was an error.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateCreateWithAllocator, (PrynState **state, PrynAllocateFunction allocate, PrynFreeFunction free, void *platform))
	/**< @brief Create a state using a custom allocator. Use #prynStateCreate if you do not need a custom allocator.
	
	The allocate function will be called once with a state field on the stack before copying the result onto the heap. Just keep in mind the the state pointer will change and the old pointer will be completely invalid.

	@param[out] state Receives the new state object, or 0 if there was an error.
	@param allocate Function called to allocate memory.
	@param free Function called to free memory.
	@param platform Memory manager-specific pointer that can be retrieved with #prynStatePlatform.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateToObject, (PrynState *state, PrynObject *output))
	/**< @brief Wraps the state into an object.

	@param output The object to write to.
	@param state The state to wrap.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynObjectToState, (PrynObject *object, PrynState **output))
	/**< @brief Convert a state object into a state pointer.

	@param object The state object; the type must be #PrynObjectTypeState or the function will fail.
	@param[out] output Written with the contained state object or 0 on failure.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateLoadLibraries, (PrynState *state, const PrynString *path))
	/**< @brief Load all libraries from the path. This will use the cache file if present, and update it automatically.

	To have the state persistently load the path in between sessions, use #prynStateAddLibraryPath instead.

	@param state The state to load the libraries into.
	@param path The path to load libraries from. This is relative to the current working directory. Libraries are not loaded recursively.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateAddLibraryPath, (PrynState *state, const PrynString *path))
	/**< @brief Add a path to the list of paths to search for libraries. If the path hasn't been added already, it will be searched.

	To search a library path without adding it to the search list, use #prynStateLoadLibraries.

	@param state The state to load libraries into.
	@param path The path to load libraries from.
	@returns #PrynResultSuccess, #PrynResultDone if the path is already in the search list, or an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateLoadCache, (PrynState *state, const PrynString *path))
	/**< @brief Load the global state from the cache file at this path.

	The cache file contains information on libraries, types, factories, mediators, and similar, library paths to load, and configuration information for all of these. Loading from a cache rather than replicating the same loading behaviour with #prynStateLoadLibraries results in faster startup time as it doesn't need to actually load the libraries until they're used.

	Once the cache file is loaded, this checks any of the paths for missing, added, or modified library files (as do all mediators if they're so configured). If they are added or modified, then the library is loaded to ensure it has not changed.

	@param state The state to load the cache into.
	@param path The path to load the cache from. This may be relative to the current working directory. If this is 0 or the string is empty, then #prynStateDefaultCachePath is used.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateSaveCache, (PrynState *state, const PrynString *path))
	/**< Save the global state to the cache file at this path.

	See #prynStateLoadCache for details on what the cache file specifically does. Monitors and tags are not saved with the state. Synthetic types, factories, mediators etc (essentially anything with a library field that is zero) are not saved.

	@param state The state to save to the cache.
	@param path The path to save the cache to. This may be relative to the current working directory. If this is 0 or the string is empty, then the path last used for #prynStateLoadCache or #prynStateSaveCache is used. If that has not happened, then #prynStateDefaultCachePath is used.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateLoadAndSaveCache, (PrynState *state, const PrynString *path))
	/**< @brief Load the cache then immediately save it.

	See #prynStateLoadCache and #prynStateSaveCache for details. */

PrynImport (PrynResult, prynStateDefaultCachePath, (PrynState *state, PrynString *output))
	/**< @brief Retrieve the default path used for saving or loading caches when the path parameter is 0 or empty.

	@param state The state to retrieve the default path for. The result is not presently dependent on the state, but it may be in the future.
	@param[out] output Written with the resultant path.
	@returns #PrynResultSuccess or an error code; see #PrynResult. */

/** @name Properties
@{ */

	PrynImport (PrynResult, prynStateTags, (PrynState *state, PrynTagList **output)) ///< Retrieve the list of tags associated with the state.
	PrynImport (PrynResult, prynStatePlatform, (PrynState *state, void **output)) ///< Retrieve a pointer  used by the memory management functions.

	PrynImport (PrynResult, prynStateSetPrintFunction, (PrynState *state, PrynPrintFunction print)) ///< Set the print function. If print is zero, then printing will have no effect.

/** @} */ // (Properties section)

/** @name Memory Management
@{ */

	#ifndef PrynAllocationTracker
	PrynImport (PrynResult, prynAllocate, (PrynState *state, size_t length, void **output)) ///< Allocate a number of bytes, outputting a pointer to the block or 0 if length is zero or if the allocation failed.
	PrynImport (PrynResult, prynAllocateCleared, (PrynState *state, size_t length, void **output)) ///< Allocate a number of bytes that is then cleared to zero, outputting a pointer to the block or 0 if length is 0 or if the allocation failed.
	PrynImport (PrynResult, prynDuplicateData, (PrynState *state, const void *source, size_t length, void **output)) ///< Create a duplicate of the data.
	PrynImport (PrynResult, prynReallocate, (PrynState *state, size_t length, void **output)) ///< Change the size of an allocation, using *output as the pointer to change and storing the new pointer in same. On failure the block size is not changed. Reallocating to zero bytes is the same as freeing the block, and *output will be set to null. If the new allocation size is larger than the original, the data after the original allocation is undefined.
	#else /* PrynAllocationTracker */
	PrynImport (PrynResult, prynAllocateTracked, (PrynState *state, size_t length, void **output, const char *filename, size_t line)) ///< Allocate a number of bytes, outputting a pointer to the block or 0 if length is zero or if the allocation failed. This is normally called by the prynAllocate macro, if allocation tracking is enabled.
	PrynImport (PrynResult, prynAllocateClearedTracked, (PrynState *state, size_t length, void **output, const char *filename, size_t line)) ///< Allocate a number of bytes that is then cleared to zero, returning a pointer to the block or 0 if length is 0 or if the allocation failed. This is normally called by the prynAllocateCleared macro.
	PrynImport (PrynResult, prynDuplicateDataTracked, (PrynState *state, const void *source, size_t length, void **output, const char *filename, size_t line)) ///< Create a duplicate of the data.
	#define prynAllocate(STATE, LENGTH, OUTPUT) prynAllocateTracked ((STATE), (LENGTH), (OUTPUT), __FILE__, __LINE__)
	#define prynAllocateCleared(STATE, LENGTH, OUTPUT) prynAllocateClearedTracked ((STATE), (LENGTH), (OUTPUT) __FILE__, __LINE__)
	#define prynDuplicateData(STATE, SOURCE, LENGTH, OUTPUT) prynDuplicateDataTracked ((STATE), (SOURCE), (LENGTH), (OUTPUT), __FILE__, __LINE__)
	#endif /* PrynAllocationTracker */

	PrynImport (PrynResult, prynFree, (PrynState *state, void *pointer)) ///< Free a previously allocated block of memory, or do nothing if pointer is 0.
	PrynImport (PrynResult, prynPrintMemoryReport, (PrynState *state)) ///< Print a report on memory usage. If allocation tracking isn't enabled, (PrynAllocationTracker isn't defined) then this does nothing and returns PrynResultDone. Otherwise this prints a brief summary on allocations. 
	PrynImport (PrynResult, prynPrintMemoryUpdates, (PrynState *state)) ///< Print information on every allocation that is current that hasn't been reported yet. This may be a very high-volume feed. If PrynAllocationTracker isn't defined, nothing is printed and PrynResultDone is returned. This also prints a memory report at the beginning.

	#define prynAllocateClearedObject(STATE, OUTPUT) prynAllocateCleared ((STATE), sizeof (**(OUTPUT)), (void **) (OUTPUT))
	#define prynDuplicateObject(STATE, SOURCE, OUTPUT) prynDuplicateData ((STATE), (SOURCE), sizeof (*(SOURCE)), (OUTPUT))

/** @} */ // (Memory Management section)

/** @name Printing
@{ */

	PrynImport (PrynResult, prynPrintString, (PrynState *state, const PrynString *string)) ///< Print a string.
	PrynImport (PrynResult, prynPrintInteger, (PrynState *state, int value)) ///< Print an integer in decimal.
	PrynImportVariadic (PrynResult, prynPrintFormat, (PrynState *state, const char *format, ...)) ///< Formatted printing, similar to printf. %s, %d, and %u are supported normally. %r is for printing PrynString. %t is for printing PrynTime.
	PrynImport (PrynResult, prynPrintFormatV, (PrynState *state, const char *format, va_list arguments)) ///< Formatted printing.

	#define prynPrintStringLiteral(STATE, STRING) do { PrynString LITERAL; prynStringLiteral (&LITERAL, (STRING)); prynPrintString (STATE, &LITERAL); } while (0) /**< @brief Print a literal string. */
	#define prynPrintStringZ(STATE, STRING) do { PrynString LITERAL; prynStringFromZ (&LITERAL, (STRING)); prynPrintString (STATE, &LITERAL); } while (0) /**< @brief Print a NUL-terminated string. */

/** @} */ // (Printing section)

PrynImport (PrynResult, prynStateResourceString, (PrynState *state, PrynResourceIndex index, PrynString *result)) ///< Return a resource string index.

PrynImport (PrynResult, prynStateIterateFactories, (PrynState *state, PrynFactory **factory))
	/**< @brief Iterate over the factories of the state.

	This is used like this:

		@code
		PrynState *state = ...; // Set to a valid state.
		PrynFactory *factory;

		for (factory = 0; !prynIterateStateFactories (state, &factory); )
			// Process this factory.
		@endcode

	@param state The state whose factories should be iterated over.
	@param[in, out] factory If *factory is zero, then this will be written with the first factory if any; otherwise it's written with the next factory after *factory. 0 is written on error or if there are no more factories.
	@returns #PrynResultSuccess if there was a factory, #PrynResultDone if iteration has completed. This may also return an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateIterateLibraries, (PrynState *state, PrynLibrary **library))
	/**< @brief Iterate over the libraries of the state.

	This is used like this:

		@code
		PrynState *state = ...; // Set to a valid state.
		PrynLibrary *library;

		for (library = 0; !prynIterateStateLibraries (state, &library); )
			// Process this library.
		@endcode

	@param state The state whose libraries should be iterated over.
	@param[in, out] library If *library is zero, then this will be written with the first library if any; otherwise it's written with the next library after *library. 0 is written on error or if there are no more libraries.
	@returns #PrynResultSuccess if there was a library, #PrynResultDone if iteration has completed. This may also return an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateIterateMediators, (PrynState *state, PrynMediator **mediator))
	/**< @brief Iterate over the mediators of the state.

	This is used like this:

		@code
		PrynState *state = ...; // Set to a valid state.
		PrynMediator *mediator;

		for (mediator = 0; !prynIterateStateMediators (state, &mediator); )
			// Process this mediator.
		@endcode

	@param state The state whose mediators should be iterated over.
	@param[in, out] mediator If *mediator is zero, then this will be written with the first mediator if any; otherwise it's written with the next mediator after *mediator. 0 is written on error or if there are no more mediators.
	@returns #PrynResultSuccess if there was a mediator, #PrynResultDone if iteration has completed. This may also return an error code; see #PrynResult. */

PrynImport (PrynResult, prynStateIterateTypes, (PrynState *state, PrynType **type))
	/**< @brief Iterate over the types of the state.

	This is used like this:

		@code
		PrynState *state = ...; // Set to a valid state.
		PrynType *type;

		for (type = 0; !prynIterateStateTypes (state, &type); )
			// Process this type.
		@endcode

	@param state The state whose types should be iterated over.
	@param[in, out] type If *type is zero, then this will be written with the first type if any; otherwise it's written with the next type after *type. 0 is written on error or if there are no more types.
	@returns #PrynResultSuccess if there was a type, #PrynResultDone if iteration has completed. This may also return an error code; see #PrynResult. */

#ifdef PrynInternalStructs
/** @brief Shared state information.
	@ingroup PrynState
*/
struct PrynState
{
#ifdef PrynInternal
/** @name Internal fields
	These fields are not normally visible to clients, and it is recommended not to use them to maximise binary compatibility. To make them available, define PrynInternal.
	@{ */

	PrynCommonObject pCommonObject; ///< Common fields you'd expect in an object, like tags and monitors.
	
	PrynLibraryList pLibraries; ///< List of the libraries.
	PrynMediatorList pMediators; ///< List of the mediators.
	PrynTypeList pTypes; ///< List of the types.
	PrynFactoryList pFactories; ///< List of the factories.
	PrynString pCachePath; ///< Most recently used cache path, or empty for none.
	
	PrynPrintFunction pPrintFunction; ///< Print text to a console. This is initialised to do nothing.
	PrynAllocateFunction pAllocateFunction; ///< Allocate a number of bytes, returning a pointer to the object or 0 if length is zero or the allocation failed. The default is a platform-specific allocator. The first time this is called, it is with a state that's held on the stack for allocating the state itself. This stack state is then copied onto the result, and the return from this function call will then be the state from that point forward.
	PrynFreeFunction pFreeFunction; ///< If pointer is non-zero, free a previously allocated block of memory. The default is platform-specific.
	void *pPlatform; ///< Platform-specific state.

	PrynString *pPaths; ///< List of paths to search for main libraries. Mediators may have their own path lists.
	size_t pPathCount; ///< Number of elements in #pPaths.
	
#ifdef PrynAllocationTracker
	PrynDList (PrynAllocation) pAllocations; ///< List of allocations made.
	size_t pAllocatedCurrent; ///< Number of bytes of allocated memory.
	size_t pAllocatedMaximum; ///< Maximum number of allocated bytes at any one time.
#endif /* PrynAllocationTracker */

/** @} */ // (Internal Fields section)
#endif /* PrynInternal */

#if __cplusplus
	inline static PrynState *Create () { PrynState *result; prynCheckErrorNull (prynStateCreate (&result)); return result; }
		/**< @brief Create a state using a default allocator.
		
		@returns The new state object. */

	inline static PrynState *Create (PrynAllocateFunction allocate, PrynFreeFunction free, void *platform = 0) { PrynState *result; prynCheckErrorNull (prynStateCreateWithAllocator (&result, allocate, free, platform)); return result; }
		/**< @brief Create a state using a custom allocator.
		
		The allocate function will be called once with a state field on the stack before copying the result onto the heap. Just keep in mind the the state pointer will change and the old pointer will be completely invalid.

		@param allocate Function called to allocate memory.
		@param free Function called to free memory.
		@param platform Memory manager-specific pointer that can be retrieved with #platform.
		@returns The new state object. */

	inline static PrynState *From (PrynObject object) { PrynState *result; prynCheckErrorNull (prynObjectToState (&object, &result)); return result; }
		/**< @brief Convert a state object into a state pointer.

		@param object The state object; the type must be #PrynObjectTypeState.
		@returns A pointer to the state. */

	inline PrynObject toObject () { PrynObject result; checkError (prynStateToObject (this, &result)); return result; }
		/**< @brief Wraps the state into an object.

		@returns An object of type #PrynObjectTypeState. */

	inline void loadLibraries (const PrynString &path) { checkError (prynStateLoadLibraries (this, &path)); }
		/**< Load all libraries from the path. This will use the cache file if present, and update it automatically.

		To have the path added to the search list so that it is searched every time the state is loaded, use #addLibraryPath instead.

		@param path The path to load libraries from. This is relative to the current working directory. Libraries are not loaded recursively.
		@returns #PrynResultSuccess or an error code; see #PrynResult. */

	inline void addLibraryPath (const PrynString &path) { checkError (prynStateAddLibraryPath (this, &path)); }
		/**< @brief Add a path to the list of paths to search for libraries. If the path hasn't been added already, it will be searched.

		To search a library path without adding it to the search list, use #loadLibraries.

		@param path The path to load libraries from. */

	inline PrynType *findType (const PrynString &id) { return PrynType::Find (this, id); } ///< Find a type, creating an unlinked type if it doesn't yet exist.

/** @name Properties
@{ */

	inline PrynTagList *tags () { PrynTagList *result; checkError (prynStateTags (this, &result)); return result; } ///< The list of tags associated with the state.
	inline void printFunction (PrynPrintFunction value) { checkError (prynStateSetPrintFunction (this, value)); } ///< Set the print function; if 0, printing has no effect.
	inline void *platform () { void *result; checkError (prynStatePlatform (this, &result)); return result; } ///< A pointer that can be used by the memory management functions.

/** @} */ // (Properties section)

/** @name Memory Management
@{ */

	inline void *allocate (size_t length) { void *result; checkError (prynAllocate (this, length, &result)); return result; } ///< Allocate a number of bytes, returning a pointer to the block or 0 if length is 0.
	inline void *allocateCleared (size_t length) { void *result; checkError (prynAllocateCleared (this, length, &result)); return result; } ///< Allocate a number of bytes that is then cleared to zero, returning a pointer to the block or 0 if length is 0.
	inline void *duplicateData (const void *source, size_t length) { void *result; checkError (prynDuplicateData (this, source, length, &result)); return result; } ///< Create a duplicate of the data, returning the copy or 0 if length is 0.
	inline void free (void *pointer); ///< Free a previously allocated block of memory, or do nothing if pointer is 0. This function cannot normally throw an exception.
	inline void *reallocate (void *data, size_t length) { checkError (prynReallocate (this, length, &data)); return data; } ///< Change the size of an allocation, using *output as the pointer to change and storing the new pointer in same. On failure the block size is not changed. Reallocating to zero bytes is the same as freeing the block, and *output will be set to null. If the new allocation size is larger than the original, the data after the original allocation is undefined.
	inline bool printMemoryReport () { return PrynIsTrue (checkError (prynPrintMemoryReport (this))); } ///< Print a report on memory usage. If allocation tracking isn't enabled (#PrynAllocationTracker isn't defined) then this does nothing and returns @b false. Otherwise this prints a brief summary on allocations. */
	inline bool printMemoryUpdates () { return PrynIsTrue (checkError (prynPrintMemoryUpdates (this))); } ///< Print information on every allocation that is current that hasn't been reported yet. This may be a very high-volume feed. If #PrynAllocationTracker isn't defined, nothing is printed and @b false is returned. This also prints a memory report at the beginning. */

/** @} */ // (Memory Management section)

/** @name Printing
	What these functions actually output is dependent on what is set in the printing function using #printFunction.
	@{ */

	inline void print (const PrynString &value) { checkError (prynPrintString (this, &value)); } ///< Print a string.
	inline void print (int value) { checkError (prynPrintInteger (this, value)); } ///< Print an integer in decimal.
	inline void print (const char *format, ...) { va_list arguments; va_start (arguments, format); checkError (prynPrintFormatV (this, format, arguments)); va_end (arguments); } ///< Formatted printing, similar to a very cut-down printf. %s, %d, and %u are supported normally, but without any arguments. %r is for printing #PrynString. %t is for printing #PrynTime. */

/** @} */ // (Printing section)

	inline PrynString resourceString (PrynResourceIndex index) { PrynString result; checkError (prynStateResourceString (this, index, &result)); return result; } ///< Return a resource string index, or a default error string if the resource cannot be found in the state.

	inline bool iterateFactories (PrynFactory **factory) { return PrynIsTrue (checkError (prynStateIterateFactories (this, factory))); }
		/**< @brief Iterate over the factories of the state.

		This is used like this:

			@code
			PrynState *state = ...; // Set to a valid state.
			PrynFactory *factory;

			for (factory = 0; state->iterateFactories (&factory); )
				// Process this factory.
			@endcode

		@param[in, out] factory If *factory is zero, then this will be written with the first factory if any; otherwise it's written with the next factory after *factory. 0 is written on error or if there are no more factories.
		@returns @b true if there is a factory, or @b false if iteration has ended. */

	inline bool iterateLibraries (PrynLibrary **library) { return PrynIsTrue (checkError (prynStateIterateLibraries (this, library))); }
		/**< @brief Iterate over the libraries of the state.

		This is used like this:

			@code
			PrynState *state = ...; // Set to a valid state.
			PrynLibrary *library;

			for (factory = 0; state->iterateLibraries (&library); )
				// Process this library.
			@endcode

		@param[in, out] library If *library is zero, then this will be written with the first library if any; otherwise it's written with the next library after *library. 0 is written on error or if there are no more libraries.
		@returns @b true if there is a library, or @b false if iteration has ended. */

	inline bool iterateMediators (PrynMediator **mediator) { return PrynIsTrue (checkError (prynStateIterateMediators (this, mediator))); }
		/**< @brief Iterate over the mediators of the state.

		This is used like this:

			@code
			PrynState *state = ...; // Set to a valid state.
			PrynMediator *mediator;

			for (mediator = 0; state->iterateMediators (state, &mediator); )
				// Process this mediator.
			@endcode

		@param[in, out] mediator If *mediator is zero, then this will be written with the first mediator if any; otherwise it's written with the next mediator after *mediator. 0 is written on error or if there are no more mediators.
		@returns @b true if there is a mediator, or @b false if iteration has ended. */

	inline bool iterateTypes (PrynType **type) { return PrynIsTrue (checkError (prynStateIterateTypes (this, type))); }
		/**< @brief Iterate over the types of the state.

		This is used like this:

			@code
			PrynState *state = ...; // Set to a valid state.
			PrynType *type;

			for (type = 0; state->iterateTypes (state, &type); )
				// Process this type.
			@endcode

		@param[in, out] type If *type is zero, then this will be written with the first type if any; otherwise it's written with the next type after *type. 0 is written on error or if there are no more types.
		@returns @b true if there is a type, or @b false if iteration has ended. */

	inline void loadCache (const PrynString &path = "") { checkError (prynStateLoadCache (this, &path)); }
		/**< @brief Load the global state from the cache file at this path.

		The cache file contains information on libraries, types, factories, mediators, and similar, library paths to load, and configuration information for all of these. Loading from a cache rather than replicating the same loading behaviour with #loadLibraries results in faster startup time as it doesn't need to actually load the libraries until they're used.

		Once the cache file is loaded, this checks any of the paths for missing, added, or modified library files (as do all mediators if they're so configured). If they are added or modified, then the library is loaded to ensure it has not changed.

		@param path The path to load the cache from. This may be relative to the current working directory. If this is empty, then #defaultCachePath is used. */

	inline void saveCache (const PrynString &path = "") { checkError (prynStateSaveCache (this, &path)); }
		/**< @brief Save the global state to the cache file at this path.

		See #saveCache for details on what the cache file specifically does. Monitors and tags are not saved with the state. Synthetic types, factories, mediators etc (essentially anything with a library field that is zero) are not saved.

		@param path The path to save the cache to. This may be relative to the current working directory. If this is empty, then the path last used for #loadCache or #saveCache is used. If that has not happened, then #defaultCachePath is used. */

	inline void loadAndSaveCache (const PrynString &path = "") { checkError (prynStateLoadAndSaveCache (this, &path)); }
		/**< @brief Load the cache then immediately save it.

		See #loadCache and #saveCache for details. */

	inline PrynString defaultCachePath () { PrynString output; checkError (prynStateDefaultCachePath (this, &output)); return output; }
		/**< @brief Retrieve the default path used for saving or loading caches when the path parameter is empty.

		The result is not presently dependent on the state, but it may be in the future. */

	inline PrynResult checkError (PrynResult result) { return prynCheckErrorBase (this, result); } ///< If the result is below zero, throw an error.

#endif /* __cplusplus */
};
#endif /* PrynInternalStructs */

/** @} */ // (PrynState group)

#endif /* PRYN_STATE_H */
